import VerEx from 'verbal-expressions';
import {
    REGEX_TAG_OPEN,
    REGEX_TAG_ATTR,
    REGEX_TAG_CLOSE,
    REGEX_TAG_TEXT,
    REGEX_TAG_END,
    REGEX_TAG_NAME,
} from './consts'
import VNode, {TextNode} from "./VNode";

const ReadState = {
    START: 0,
    TAG_OPEN: 1,
    TAG_ATTR: 2,
    TAG_CLOSE: 3,
    TAG_END: 4
};

class Parser {
    _root;
    _text;
    _state = ReadState.START;
    _nodeStack = [];

    constructor(text) {
        this._text = text;
    }

    set text(text) {
        this._text = text;
    }

    get text() {
        return this._text;
    }


    /**
     * 当前状态
     */
    set state(state) {
        this._state = state;
    }

    /**
     * 当前状态
     * @returns {*}
     */
    get state() {
        return this._state;
    }

    /**
     * 当前节点
     * @returns {*}
     */
    get node() {
        if (this._nodeStack.length > 0) {
            return this._nodeStack[this._nodeStack.length - 1];
        }
        return null;
    }

    pushNode(node) {
        this._nodeStack.push(node)
    }

    popNode() {
        this._root = this._nodeStack.pop();
        return this._root;
    }

    parse() {
        this.detect();
        return this._root;
    }

    detect() {
        this.text = this.text.trim();
        let currentLength = this.text.length;
        while (this.text.length > 0) {
            this.text = this.text.trim();
            this.detectTagOpen();
            this.detectTagAttr();
            this.detectTagClose();
            this.detectTagEnd();
            this.detectText();
            if (currentLength === this.text.length) {
                console.error("Template Error: ", this.text);
                break;
            }
        }
    }

    /**
     * 标签打开
     * @returns {number}
     */
    detectTagOpen() {
        if (this.state !== ReadState.TAG_OPEN) {
            // 检测是否进入标签开始阶段
            let rex = REGEX_TAG_OPEN.exec(this.text);
            if (rex && rex.index === 0) {
                let node = new VNode(rex);
                if (this.node) this.node.addChild(node);
                this.pushNode(node);
                this.text = this.text.substr(rex[0].length);
                this.state = ReadState.TAG_OPEN;
            }
            return rex && rex.index;
        }
        this.log();
    }

    /**
     * 标签属性
     * @returns {number}
     */
    detectTagAttr() {
        if (this.state === ReadState.TAG_OPEN) {
            let node = this.node;
            let rex = REGEX_TAG_ATTR.exec(this.text);
            if (rex && rex.index === 0) {
                node.addAttr(rex[1], rex[2]);
                this.text = this.text.substr(rex[0].length);
            }
        }
        return 0;
    }

    /**
     * 标签关闭
     * @returns {number}
     */
    detectTagClose() {
        if (this.state === ReadState.TAG_OPEN) {
            let rex = REGEX_TAG_CLOSE.exec(this.text);
            if (rex && rex.index === 0) {
                if (rex[0] === "/>") {
                    this.popNode();
                    this.state = ReadState.TAG_END;
                } else {
                    this.state = ReadState.TAG_CLOSE;
                }
                this.text = this.text.substr(rex[0].length);
            }
            return rex && rex.index;
        }
        this.log();
    }

    /**
     * 标签结束
     * @returns {number}
     */
    detectTagEnd() {
        if (this.node && this.state !== ReadState.TAG_OPEN) {
            let rex = REGEX_TAG_END.exec(this.text);
            if (rex && rex.index === 0) {
                this.popNode();
                this.state = ReadState.TAG_END;
                this.text = this.text.substr(rex[0].length);
            }
            return rex && rex.index;
        }
        this.log();
    }

    /**
     * 字符串文本
     * @returns {number}
     */
    detectText() {
        if (this.state !== ReadState.TAG_OPEN) {
            let nextStartRex = VerEx()
                .then(/\s*/g)
                .then('<')
                .then(REGEX_TAG_NAME)
                .toRegExp().exec(this.text);
            let nextEndRex = VerEx()
                .then(/\s*/g)
                .then('</')
                .beginCapture()
                .then(REGEX_TAG_NAME)
                .then('>')
                .endCapture()
                .toRegExp().exec(this.text);
            let index = this.text.length;
            if (nextStartRex) {
                index = Math.min(nextStartRex.index, index)
            }
            if (nextEndRex) {
                index = Math.min(nextEndRex.index, index);
            }
            if (index > 0) {
                let node = new TextNode(undefined, this.text.substr(0, index));
                this.node.addChild(node);
                this.text = this.text.substr(index);
                return index;
            }
        }
        this.log();
    }

    log() {}
}

export const parse = function parseHTML(jsx) {
    return new Parser(jsx).parse();
};